#ifndef PARTICLE_H
#define PARTICLE_H

#include "vector"

#include "ngl/NGLInit.h"
#include "ngl/Vector.h"

#include "Spring.h"

/// @file Particle.h
/// @brief represents the unit mass of the cloth structure
/// @author Perseedoss Rajiv
/// @version 1.0
/// @date 12.04.11
/// Revision History :
/// Initial Version 12.04.11
/// @class Particle
/// @brief the unit mass object of the cloth structure

class Spring;

class Particle
{
public:

    /// @brief ctor
    /// @param[in] _id the unique id of the particle
    /// @param[in] _mass the mass of the particle
    /// @param[in] _moveable the toggle for moveable property
    Particle
        (
            const int _id = 0,
            const float _mass = 1,
            const bool _moveable = true
        );

    /// @brief dtor
    ~Particle();

    /// @brief return the id of the particle
    inline int getId() const { return m_id; }

    /// @brief return the mass of the particle
    inline float getMass() const { return m_mass; }
    inline void setMass(const float _m) { m_mass = _m; }

    /// @brief return the initial position of the particle
    inline ngl::Vector getInitialPosition() const { return m_initialPosition; }

    /// @brief set the initial position of the particle
    /// @param[in] _p the position to set to
    inline void setInitialPosition(const ngl::Vector _p) { m_initialPosition = _p; }

    /// @brief return the last last position of the particle
    inline ngl::Vector getLastLastPosition() const { return m_lastLastPosition; }

    /// @brief return the last position of the particle
    inline ngl::Vector getLastPosition() const { return m_lastPosition; }

    /// @brief return the current position of the particle
    inline ngl::Vector getPosition() const { return m_position; }

    /// @brief set the position of the particle
    /// @param[in] _p the position to set to
    void setPosition(const ngl::Vector _p);

    /// @brief update the position of the particle
    /// @param[in] _p the position to update to
    void updatePosition(const ngl::Vector _p);

    /// @brief set the current position of the particle
    /// @param[in] _p the position to set to
    inline void setCurrentPosition(const ngl::Vector _p) { m_position = _p; }

    /// @brief return the current velocity of the particle
    inline ngl::Vector getVelocity() const { return m_velocity; }

    /// @brief set the velocity of the particle
    /// @param[in] _v the velocity to set to
    void setVelocity(const ngl::Vector _v);

    /// @brief set the current velocity of the particle
    /// @param[in] _v the velocity to set to
    inline void setCurrentVelocity(const ngl::Vector _v) { m_velocity = _v; }

    /// @brief return the last velocity of the particle
    inline ngl::Vector getLastVelocity() const { return m_lastVelocity; }

    /// @brief return the net force on the particle
    inline ngl::Vector getNetForce() const { return m_netForce; }

    /// @brief set the net force on the particle
    /// @param[in] _f the force to set to
    inline void setNetForce(const ngl::Vector _f) { m_netForce = _f; }


    /// @brief return the toggle flag for moveability of the particle
    inline bool getMoveable() const { return m_moveable; }

    /// @brief set the toggle flag for moveability of the particle
    /// @param[in] _s the toggle flag value
    inline void setMoveable(const bool _s) { m_moveable = _s; }

    /// @brief return the list of connected springs to the particle
    inline std::vector<Spring*>* getNeighbourList() const { return m_neighbourList; }

    /// @brief clears the net force on the  particle
    inline void clearNetForce() { m_netForce = 0; }

    /// @brief adds to the net force of the particle
    /// @param[in] _f the force to be added
    inline void addToNetForce(const ngl::Vector _f) { m_netForce += _f; }

    /// @brief return a clone of the particle
    Particle clone();

private:
    /// @brief unique id of the particle
    int m_id;

    /// @brief mass of the particle
    float m_mass;

    /// @brief position of the particle
    ngl::Vector m_position;

    /// @brief velocity of the particle
    ngl::Vector m_velocity;

    /// @brief initial position of the particle
    ngl::Vector m_initialPosition;

    /// @brief last last position of the particle
    ngl::Vector m_lastLastPosition;

    /// @brief last position of the particle
    ngl::Vector m_lastPosition;

    /// @brief last velocity of the particle
    ngl::Vector m_lastVelocity;

    /// @brief net force on the particle
    ngl::Vector m_netForce;

    /// @brief flag for moveability
    bool m_moveable;

    /// @brief list of connected springs
    std::vector<Spring*>* m_neighbourList;

};

#endif // PARTICLE_H
